package com.mate.cloud.xml;

import org.dom4j.*;
import org.dom4j.io.DOMReader;
import org.dom4j.io.SAXReader;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.Assert;
import org.xml.sax.InputSource;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;
import java.util.Iterator;
import java.util.List;
/**
 * 测试命名空间的使用
 * @author:         MI
 * @email:          448341911@qq.com
 * @createTime:     2024/6/4 15:58
 * @updateUser:     MI
 * @updateTime:     2024/6/4 15:58
 * @updateRemark:   修改内容
 * @version:        v1.0
 */
public class NamespacesTest extends AbstractTestCase {

    // Test case(s)
    // -------------------------------------------------------------------------
    @Test
    public void testNamespaces() throws Exception {
        testNamespaces(document);
        testNamespaces(saxRoundTrip(document));
        testNamespaces(domRoundTrip(document));
    }

    public void testNamespaces(Document document) throws Exception {
        Document doc2 = (Document) document.clone();

        Element root = doc2.getRootElement();
        assertNamespace(root.getNamespace(), "",
                "http://www.w3.org/2001/XMLSchema");
        assertEquals("xmlns=\"http://www.w3.org/2001/XMLSchema\"", root
                .getNamespace().asXML());
        assertEquals("namespace::*[name()='']", root.getNamespace().getPath());
        assertEquals("namespace::*[name()='']", root.getNamespace()
                .getUniquePath());

        List additionalNS = root.additionalNamespaces();
        assertTrue("at least one additional namespace", (additionalNS != null)
                && (additionalNS.size() > 0));

        Namespace ns = (Namespace) additionalNS.get(0);
        assertNamespace(ns, "t", "http://www.w3.org/namespace/");
        assertEquals("xmlns:t=\"http://www.w3.org/namespace/\"", ns.asXML());
        assertEquals("namespace::t", ns.getPath());
        assertEquals("namespace::t", ns.getUniquePath());

        Node node = root.node(0);
        assertTrue("First node is a namespace", node instanceof Namespace);

        // now lets try change the namespace
        root.remove(ns);
        root.addNamespace("t", "myNewURI");

        additionalNS = root.additionalNamespaces();
        assertTrue("at least one additional namespace", (additionalNS != null)
                && (additionalNS.size() > 0));

        ns = (Namespace) additionalNS.get(0);
        assertNamespace(ns, "t", "myNewURI");

        // lets test the list is backed
        additionalNS.remove(0);
        additionalNS.add(Namespace.get("t", "myNewURI-2"));

        additionalNS = root.additionalNamespaces();
        assertTrue("at least one additional namespace", (additionalNS != null)
                && (additionalNS.size() > 0));

        ns = (Namespace) additionalNS.get(0);
        assertNamespace(ns, "t", "myNewURI-2");

        additionalNS.clear();
        root.addNamespace("t", "myNewURI");

        additionalNS = root.additionalNamespaces();
        assertTrue("at least one additional namespace", (additionalNS != null)
                && (additionalNS.size() > 0));

        ns = (Namespace) additionalNS.get(0);
        assertNamespace(ns, "t", "myNewURI");

        log("Namespaces: " + additionalNS);
        log("XML is now");
        log(root.asXML());
    }




    /**
     *
     * @throws Exception
     */
    @Test
    public void testNamespaceForPrefix() throws Exception {
        testNamespaceForPrefix(document);
        testNamespaceForPrefix(saxRoundTrip(document));
        testNamespaceForPrefix(domRoundTrip(document));
    }
    public void testNamespaceForPrefix(Document document) throws Exception {
        Element root = document.getRootElement();
        Namespace ns = root.getNamespaceForPrefix("t");

        assertNamespace(ns, "t", "http://www.w3.org/namespace/");

        Element element = (Element) root.elements().get(0);
        Namespace ns2 = element.getNamespaceForPrefix("t");

        assertNamespace(ns2, "t", "http://www.w3.org/namespace/");
        assertTrue("Same namespace instance returned", ns == ns2);

        log("found: " + ns.asXML());
    }

    /**
     * 测试默认命名空间
     * @throws Exception
     */
    @Test
    public void testNamespaceForDefaultPrefix() throws Exception {
      //  Document document = getDocument("classpath:xml/test/defaultNamespace.xml");
        ResourceLoader resourceLoader = new DefaultResourceLoader();
        Resource resource = resourceLoader.getResource("classpath:xml/test/defaultNamespace.xml");
        Assert.isTrue(resource.exists(), "XML file not found");
        SAXReader saxReader = SAXReader.createDefault();
        Document document = getDocument(resource.getInputStream(), saxReader);

        testNamespaceForDefaultPrefix(document);
        testNamespaceForDefaultPrefix(saxRoundTrip(document));
        testNamespaceForDefaultPrefix(domRoundTrip(document));
    }
    public void testNamespaceForDefaultPrefix(Document document)
            throws Exception {
        List list = document.selectNodes("//*");

        for (Iterator iter = list.iterator(); iter.hasNext();) {
            Element element = (Element) iter.next();
            Namespace ns = element.getNamespaceForPrefix("");
            assertNamespace(ns, "", "dummyNamespace");
            ns = element.getNamespaceForPrefix(null);
            assertNamespace(ns, "", "dummyNamespace");
            log("found: " + ns.asXML());
        }
    }

    @Test
    public void testAttributeDefaultPrefix() throws Exception {


        ResourceLoader resourceLoader = new DefaultResourceLoader();
        Resource resource = resourceLoader.getResource("classpath:xml/test/soap3.xml");
        Assert.isTrue(resource.exists(), "XML file not found");
        SAXReader saxReader = SAXReader.createDefault();
        Document document = getDocument(resource.getInputStream(), saxReader);

        testAttributeDefaultPrefix(document);
        testAttributeDefaultPrefix(saxRoundTrip(document));
        testAttributeDefaultPrefix(domRoundTrip(document));
    }
    public void testAttributeDefaultPrefix(Document document) throws Exception {
        List list = document.selectNodes("//@*[local-name()='actor']");

        assertTrue("Matched at least one 'actor' attribute", list.size() > 0);

        for (Iterator iter = list.iterator(); iter.hasNext();) {
            Attribute attribute = (Attribute) iter.next();

            log("found: " + attribute.asXML());

            Element element = attribute.getParent();
            assertTrue("Attribute has a parent", element != null);

            Namespace ns = element.getNamespaceForPrefix("");

            String uri = "http://schemas.xmlsoap.org/soap/envelope/";
            assertNamespace(ns, "", uri);

            Namespace ns2 = attribute.getNamespace();

            // Note that namespaces do not inherit the default namespace!
            assertNamespace(ns2, "", "");
        }
    }

    protected Document saxRoundTrip(Document document) throws Exception {
        return DocumentHelper.parseText(document.asXML());
    }
    protected Document domRoundTrip(Document document) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);

        DocumentBuilder builder = factory.newDocumentBuilder();
        org.w3c.dom.Document domDocument = builder.parse(new InputSource(
                new StringReader(document.asXML())));

        // now lets read it back as a DOM4J object
        DOMReader domReader = new DOMReader();

        return domReader.read(domDocument);
    }
    protected void assertNamespaces(List elements, String prefix, String uri)
            throws Exception {
        for (Iterator iter = elements.iterator(); iter.hasNext();) {
            Element element = (Element) iter.next();
            assertNamespace(element.getNamespace(), prefix, uri);
        }
    }
    protected void assertNamespace(Namespace ns, String prefix, String uri)
            throws Exception {
        assertEquals("namespace prefix", prefix, ns.getPrefix());
        assertEquals("namespace URI", uri, ns.getURI());
    }

    // Implementation methods
    // -------------------------------------------------------------------------
    @BeforeEach
    protected void setUp() throws Exception {
        super.setUp();

        ResourceLoader resourceLoader = new DefaultResourceLoader();
        Resource resource = resourceLoader.getResource("/xml/test/test_schema.xml");
        Assert.isTrue(resource.exists(), "XML file not found");
        SAXReader saxReader = SAXReader.createDefault();
        document = getDocument(resource.getInputStream(), saxReader);

    }
}
